# SPDX-License-Identifier: Apache-2.0

include_guard(GLOBAL)

# CMake version 3.20 is the real minimum supported version.
#
# Under these restraints we use a second 'cmake_minimum_required'
# invocation in every toplevel CMakeLists.txt.
cmake_minimum_required(VERSION 3.20.0)

# CMP0002: "Logical target names must be globally unique"
cmake_policy(SET CMP0002 NEW)

# CMP0079: "target_link_libraries() allows use with targets in other directories"
cmake_policy(SET CMP0079 NEW)

if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
  message(FATAL_ERROR "Source directory equals build directory.\
    In-source builds are not supported.\
    Please specify a build directory, e.g. cmake -Bbuild -H.")
endif()

set(SEMINIX_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH "Kernel Source Directory")
set(SEMINIX_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH "Kernel Binary Directory")
message(STATUS "Kernel source: ${SEMINIX_SOURCE_DIR}")

set(AUTOCONF_H ${SEMINIX_BINARY_DIR}/include/generated/autoconf.h)
# Re-configure (Re-execute all CMakeLists.txt code) when autoconf.h changes
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${AUTOCONF_H})

#
# Import more CMake functions and macros
#
include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
include(${SEMINIX_SOURCE_DIR}/scripts/extensions.cmake)
include(${SEMINIX_SOURCE_DIR}/scripts/git.cmake)
include(${SEMINIX_SOURCE_DIR}/scripts/version.cmake)

seminix_check_cache(SEMINIX_SOURCE_DIR REQUIRED)
seminix_check_cache(SEMINIX_BINARY_DIR REQUIRED)
message(STATUS "Kernel Output: ${SEMINIX_BINARY_DIR}")

include(${SEMINIX_SOURCE_DIR}/scripts/python.cmake)
include(${SEMINIX_SOURCE_DIR}/scripts/ccache.cmake)

if(NOT DEFINED USER_CACHE_DIR)
	find_appropriate_cache_directory(USER_CACHE_DIR)
  set(USER_CACHE_DIR ${USER_CACHE_DIR} CACHE PATH "")
endif()
message(STATUS "Cache files will be written to: ${USER_CACHE_DIR}")

# Check that ARCH has been provided.
set(ENV_ARCH $ENV{ARCH})
if ((NOT DEFINED ARCH) AND (DEFINED ENV_ARCH))
  set(ARCH ${ENV_ARCH} CACHE STRING "")
endif()

if (NOT DEFINED ARCH)
  message(FATAL_ERROR "\nARCH is not defined, it is a required platform variable.
Example:
  -DARCH=arm64 or export ARCH=arm64
")
endif()
message(STATUS "ARCH: ${ARCH}")

# Equivalent to rm -rf build/*
add_custom_target(
  pristine
  COMMAND ${CMAKE_COMMAND} -DBINARY_DIR=${SEMINIX_BINARY_DIR}
    -DSOURCE_DIR=${SEMINIX_SOURCE_DIR}
    -P ${SEMINIX_SOURCE_DIR}/scripts/pristine.cmake
)

# Prevent CMake from testing the toolchain
set(CMAKE_C_COMPILER_FORCED   1)
set(CMAKE_CXX_COMPILER_FORCED 1)

if(NOT DEFINED SEMINIX_TOOLCHAIN)
	set(SEMINIX_TOOLCHAIN $ENV{SEMINIX_TOOLCHAIN})
endif()

if(NOT SEMINIX_TOOLCHAIN AND
    (CROSS_COMPILE OR (DEFINED ENV{CROSS_COMPILE})))
  set(SEMINIX_TOOLCHAIN cross-compile)
endif()

if(NOT DEFINED SEMINIX_TOOLCHAIN)
  message(FATAL_ERROR "No toolchain defining the available tools, The sample:
    SEMINIX_TOOLCHAIN=llvm/host
")
endif()

# dtc is an optional dependency
find_program(DTC dtc)

if(DTC)
  # Parse the 'dtc --version' output to find the installed version.
  set(MIN_DTC_VERSION 1.4.6)
  execute_process(
    COMMAND
    ${DTC} --version
    OUTPUT_VARIABLE dtc_version_output
    ERROR_VARIABLE  dtc_error_output
    RESULT_VARIABLE dtc_status
  )

  if(${dtc_status} EQUAL 0)
    string(REGEX MATCH "Version: DTC ([0-9]+[.][0-9]+[.][0-9]+).*" out_var ${dtc_version_output})

    # Since it is optional, an outdated version is not an error. If an
    # outdated version is discovered, print a warning and proceed as if
    # DTC were not installed.
    if(${CMAKE_MATCH_1} VERSION_GREATER ${MIN_DTC_VERSION})
      message(STATUS "Found dtc: ${DTC} (found suitable version \"${CMAKE_MATCH_1}\", minimum required is \"${MIN_DTC_VERSION}\")")
    else()
      message(WARNING "Could NOT find dtc: Found unsuitable version \"${CMAKE_MATCH_1}\", but required is at least \"${MIN_DTC_VERSION}\" (found ${DTC}). Optional devicetree error checking with dtc will not be performed.")
      set(DTC DTC-NOTFOUND)
    endif()
  else()
    message(WARNING "Could NOT find working dtc: Found dtc (${DTC}), but failed to load with:\n ${dtc_error_output}")
    set(DTC DTC-NOTFOUND)
  endif()
endif()

find_program(SHELL sh REQUIRED)
find_program(GREP grep REQUIRED)
find_program(BC bc REQUIRED)

include(${SEMINIX_SOURCE_DIR}/scripts/target_toolchain.cmake)

enable_language(C CXX ASM)

include(${SEMINIX_SOURCE_DIR}/scripts/kconfig.cmake)
include(${SEMINIX_SOURCE_DIR}/scripts/dts.cmake)

if(CONFIG_BUILD_VERSION_AUTO)
	set(SEMINIX_VERSION_STRING "\"${SEMINIX_VERSION_PREFIX}${CONFIG_LOCALVERSION}-${BUILD_VERSION}\"")
else()
	set(SEMINIX_VERSION_STRING "\"${SEMINIX_VERSION_PREFIX}${CONFIG_LOCALVERSION}\"")
endif()
configure_file(${SEMINIX_SOURCE_DIR}/version.h.in ${SEMINIX_BINARY_DIR}/include/generated/version.h)
# Re-configure (Re-execute all CMakeLists.txt code) when autoconf.h changes
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${SEMINIX_SOURCE_DIR}/VERSION)

seminix_check_compiler_flag(C "" toolchain_is_ok)
assert(toolchain_is_ok "The toolchain is unable to build a dummy C file. See CMakeError.log.")
seminix_check_compiler_flag(ASM "" toolchain_is_ok)
assert(toolchain_is_ok "The toolchain is unable to build a dummy ASM file. See CMakeError.log.")

set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug;Release;RelWithDebInfo;MinSizeRel")
mark_as_advanced(CLEAR CMAKE_BUILD_TYPE)
